﻿#include <sstream>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QFile>
#include <QHttpMultiPart>
#include "Netdisc.h"

Netdisc::Netdisc() {
	httpMgr = std::make_shared<QNetworkAccessManager>();
}

QString Netdisc::get(const QString& url) {
	QNetworkRequest requestInfo;
	requestInfo.setUrl(QUrl(url));
	QNetworkReply* reply = this->httpMgr->get(requestInfo);
	QObject::connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
	eventLoop.exec();
	QObject::disconnect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
	if (reply->error() != QNetworkReply::NoError) {
		QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
		qDebug() << "reply error. url:" << url << ", statusCode:" << statusCode.toInt() << ", error code:" << (int)reply->error() << ", error info:" << qPrintable(reply->errorString());
	}
	//请求返回的结果
	QByteArray responseByte = reply->readAll();
	return responseByte;
}

// 发送post请求
QString Netdisc::post(const QString& url, const QString& content) {
	QNetworkRequest requestInfo;
	requestInfo.setUrl(QUrl(url));
	QString header = "application/x-www-form-urlencoded";
	requestInfo.setHeader(QNetworkRequest::ContentTypeHeader, header);
	// requestInfo.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
	requestInfo.setHeader(QNetworkRequest::UserAgentHeader, QVariant("pan.baidu.com"));
	qDebug() << "content.length:" << content.length();
	requestInfo.setHeader(QNetworkRequest::ContentLengthHeader, content.length());
	QNetworkReply* reply = this->httpMgr->post(requestInfo, content.toLatin1());
	QObject::connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
	eventLoop.exec();
	QObject::disconnect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
	if (reply->error() != QNetworkReply::NoError) {
		QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
		qDebug() << "reply error. url:" << url << ", statusCode:" << statusCode.toInt() << ", error code:" << (int)reply->error() << ", error info:" << qPrintable(reply->errorString()) << " rawHeaderPairs:" << reply->rawHeaderPairs();
	}
	//请求返回的结果
	QByteArray responseByte = reply->readAll();
	return responseByte;
}

// 发送put请求
QString Netdisc::put(const QString& url, const QString& content) {
	QNetworkRequest requestInfo;
	requestInfo.setUrl(QUrl(url));
	QString header = "application/x-www-form-urlencoded";
	requestInfo.setHeader(QNetworkRequest::ContentTypeHeader, header);
	// requestInfo.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
	requestInfo.setHeader(QNetworkRequest::UserAgentHeader, QVariant("pan.baidu.com"));
	qDebug() << "content.length:" << content.length();
	requestInfo.setHeader(QNetworkRequest::ContentLengthHeader, content.length());
	QNetworkReply* reply = this->httpMgr->put(requestInfo, content.toLatin1());
	QObject::connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
	eventLoop.exec();
	QObject::disconnect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
	if (reply->error() != QNetworkReply::NoError) {
		QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
		qDebug() << "reply error. url:" << url << ", statusCode:" << statusCode.toInt() << ", error code:" << (int)reply->error() << ", error info:" << qPrintable(reply->errorString()) << " rawHeaderPairs:" << reply->rawHeaderPairs();
	}
	//请求返回的结果
	QByteArray responseByte = reply->readAll();
	return responseByte;
}

void Netdisc::readToken() {
	QFile file("meter_query_token.json");
	if (!file.open(QIODevice::ReadWrite)) {
		qDebug() << "meter_query_token.json open error";
		return;
	}
	qDebug() << "readToken meter_query_token.json open!";
	auto content = file.readAll();
	QJsonParseError errRpt;
	QJsonDocument  rootDoc = QJsonDocument::fromJson(content, &errRpt); // 字符串格式化为JSON
	if (errRpt.error != QJsonParseError::NoError)
	{
		qDebug() << "JSON格式错误";
		return;
	}
	else    // JSON格式正确
	{
		QJsonObject rootObj = rootDoc.object();
		auto it = rootObj.find("refreshToken");
		if (it != rootObj.end()) {
			auto value = it.value();
			if (value.isString()) {
				this->refreshToken = value.toString();
				qDebug() << "refreshToken:" << this->refreshToken;
			}
		}
		it = rootObj.find("accessToken");
		if (it != rootObj.end()) {
			auto value = it.value();
			if (value.isString()) {
				this->accessToken = value.toString();
				qDebug() << "accessToken:" << this->accessToken;
			}
		}
	}
	return;
}

void Netdisc::saveToken() {
	QJsonObject object
	{
		{"refreshToken", refreshToken},
		{"accessToken", accessToken}
	};
	QJsonDocument jsonDoc;
	jsonDoc.setObject(object);
	QFile file("meter_query_token.json");
	if (!file.open(QIODevice::ReadWrite)) {
		qDebug() << "meter_query_token.json open error";
		return;
	}
	qDebug() << "meter_query_token.json open!";
	file.resize(0);
	file.write(jsonDoc.toJson());
	file.close();
}

void Netdisc::updateToken() {
	std::string refreshAccessToken = constructRefreshAccessToken(this->refreshToken.toStdString());
	auto refreshAccessTokenRsp = get(QString::fromStdString(refreshAccessToken));
	parseRefreshAccessTokenRsp(refreshAccessTokenRsp);
}

// 解析刷新AccessToken回报
bool Netdisc::parseRefreshAccessTokenRsp(QString content) {
	QJsonParseError errRpt;
	QJsonDocument  rootDoc = QJsonDocument::fromJson(content.toLatin1(), &errRpt); // 字符串格式化为JSON
	if (errRpt.error != QJsonParseError::NoError)
	{
		qDebug() << "JSON格式错误";
		return false;
	}
	else    // JSON格式正确
	{
		QJsonObject rootObj = rootDoc.object();
		auto it = rootObj.find("error");
		if (it != rootObj.end()) {
			qDebug() << "RefreshAccessToken error. content:" << content;
			return false;
		}
		it = rootObj.find("refresh_token");
		if (it != rootObj.end()) {
			auto value = it.value();
			if (value.isString()) {
				this->refreshToken = value.toString();
				qDebug() << "refreshToken:" << this->refreshToken;
			}
		}
		it = rootObj.find("access_token");
		if (it != rootObj.end()) {
			auto value = it.value();
			if (value.isString()) {
				this->accessToken = value.toString();
				qDebug() << "access_token:" << this->accessToken;
			}
		}
	}
	//  保存token到文件
	saveToken();
	return true;
}

// 构建refreshAccessToken
std::string Netdisc::constructRefreshAccessToken(std::string refreshToken) {
	std::ostringstream oss;
	oss << "https://openapi.baidu.com/oauth/2.0/token?grant_type=refresh_token&refresh_token=";
	oss << refreshToken;
	oss << "&client_id=0Phk8cl7tf5DVKUrBtn1jMBMgo58jyL1&client_secret=vAUcAEpm0Zaf4GDiCrgwNR7T4ZZQXaAk";
	return oss.str();
}

QString Netdisc::getRefreshToken() {
	return refreshToken;
}

// 上传文件
bool Netdisc::uploadFile(const QString& fileName, const QByteArray& content) {
	// 预创建
	if (!uploadFilePrecreate(fileName, content)) {
		qDebug() << "precreate error, fileName:" << fileName << ", content:" << content;
		return false;
	}
	// 分片上传
	if (!uploadFileSuperFile(fileName, content)) {

	}
	// 确认
	if (!uploadFileCreate(fileName, content)) {

	}
	return true;
}

// 预创建
bool Netdisc::uploadFilePrecreate(const QString& fileName, const QByteArray& content) {
	std::ostringstream oss;
	oss << "http://pan.baidu.com/rest/2.0/xpan/file?method=precreate&access_token=";
	oss << this->accessToken.toStdString();
	QString url = QString::fromStdString(oss.str());
	qDebug() << "url:" << url;
	oss.str("");
	oss << "path=/apps/meter_query/" << fileName.toStdString();
	oss << "&size=" << content.size();
	QCryptographicHash hash(QCryptographicHash::Md5);
	hash.addData(content, content.size());
	auto md5Str = QString(hash.result().toHex()).toStdString();
	oss << "&isdir=0&autoinit=1&rtype=3&block_list=[\"" << md5Str << "\"]";
	oss << "&content-md5=" << md5Str;
	oss << "&slice-md5=" << md5Str;
	QString data = QString::fromStdString(oss.str());
	qDebug() << "data:" << data;
	auto responseByte = post(url, data);
	qDebug() << responseByte;
	QJsonParseError errRpt;
	QJsonDocument  rootDoc = QJsonDocument::fromJson(responseByte.toLatin1(), &errRpt); // 字符串格式化为JSON
	if (errRpt.error != QJsonParseError::NoError)
	{
		qDebug() << "JSON格式错误";
		return false;
	}
	else    // JSON格式正确
	{
		QJsonObject rootObj = rootDoc.object();
		auto it = rootObj.find("errno");
		int errCode = 0;
		if (it != rootObj.end()) {
			auto value = it.value();
			if (value.isDouble()) {
				errCode = value.toInt();
				qDebug() << "errCode:" << errCode;
			}
		}
		if (errCode != 0) {
			qDebug() << "precreate error, errCode:" << errCode;
			return false;
		}
		it = rootObj.find("uploadid");
		if (it != rootObj.end()) {
			auto value = it.value();
			if (value.isString()) {
				this->uploadId = value.toString();
				qDebug() << "uploadId:" << this->uploadId;
			}
		}
		else {
			qDebug() << "precreate error, has not uploadid.";
			return false;
		}
	}
	return true;
}

// 分片上传
bool Netdisc::uploadFileSuperFile(const QString& fileName, const QByteArray& content) {
	std::ostringstream oss;
	oss << "https://d.pcs.baidu.com/rest/2.0/pcs/superfile2?access_token=" << accessToken.toStdString();
	oss << "&method=upload&type=tmpfile&path=/apps/meter_query/" << fileName.toStdString();
	oss << "&uploadid=" << uploadId.toStdString();
	oss << "&partseq=0";
	QString url = QString::fromStdString(oss.str());
	qDebug() << "url:" << url;
	oss.str("");
	auto responseByte = put(url, content);
	qDebug() << responseByte;
	QJsonParseError errRpt;
	QJsonDocument  rootDoc = QJsonDocument::fromJson(responseByte.toLatin1(), &errRpt); // 字符串格式化为JSON
	if (errRpt.error != QJsonParseError::NoError)
	{
		qDebug() << "JSON格式错误";
		return false;
	}
	else    // JSON格式正确
	{
		QJsonObject rootObj = rootDoc.object();
		auto it = rootObj.find("errno");
		int errCode = 0;
		if (it != rootObj.end()) {
			auto value = it.value();
			if (value.isDouble()) {
				errCode = value.toInt();
				qDebug() << "errCode:" << errCode;
			}
		}
		if (errCode != 0) {
			qDebug() << "precreate error, errCode:" << errCode;
			return false;
		}
		it = rootObj.find("md5");
		if (it != rootObj.end()) {
			auto value = it.value();
			if (value.isString()) {
				this->md5sum = value.toString();
				qDebug() << "md5sum:" << this->md5sum;
			}
		}
		else {
			qDebug() << "superFile error, has not md5.";
			return false;
		}
	}
	
	return true;
}

// 创建文件
bool Netdisc::uploadFileCreate(const QString& fileName, const QByteArray& content) {
	std::ostringstream oss;
	oss << "https://pan.baidu.com/rest/2.0/xpan/file?method=create&access_token=" << accessToken.toStdString();
	oss << "&method=upload&type=tmpfile&path=/apps/meter_query/" << fileName.toStdString();
	oss << "&uploadid=" << uploadId.toStdString();
	oss << "&partseq=0";
	QString url = QString::fromStdString(oss.str());
	qDebug() << "url:" << url;
	oss.str("");
	oss << "path=/apps/meter_query/" << fileName.toStdString();
	oss << "&size=" << content.size();
	QCryptographicHash hash(QCryptographicHash::Md5);
	hash.addData(content, content.size());
	auto md5Str = QString(hash.result().toHex()).toStdString();
	oss << "&isdir=0&rtype=3&uploadid=" << uploadId.toStdString();
	oss << "&block_list=[\"" << this->md5sum.toStdString() << "\"]";
	QString data = QString::fromStdString(oss.str());
	qDebug() << "data:" << data;
	auto responseByte = post(url, data);
	qDebug() << responseByte;
	return true;
}